﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Lhz.Data.Linq
{
    public static class QueryableExpansion
    {
        public static List<T> Execute<T>(this IQueryable<T> query, Pagination pagination)
        {
            if (pagination != null)
            {
                pagination.Count = query.Count();
                query = query.Skip((pagination.Index - 1) * pagination.Size);
                query = query.Take(pagination.Size);
            }
            return query.ToList();
        }

        public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, List<OrderBy> orderBies)
        {
            if (orderBies != null)
            {
                var entityType = typeof(T);
                var parameter = Expression.Parameter(entityType, "r");
                foreach (var sorting in orderBies)
                {
                    var columnNames = sorting.PropertyName.Split('.');
                    PropertyInfo property = null;
                    Expression propertyAccess = null;
                    foreach (var columnName in columnNames)
                    {
                        Type parentType;
                        if (property == null)
                        {
                            parentType = entityType;
                        }
                        else
                        {
                            parentType = property.PropertyType;
                        }
                        Dictionary<string, PropertyInfo> sameProperties = new Dictionary<string, PropertyInfo>();
                        foreach (var propertyInfo in parentType.GetProperties())
                        {
                            if (propertyInfo.Name.ToLower() == columnName.ToLower())
                            {
                                sameProperties.Add(propertyInfo.Name, propertyInfo);
                            }
                        }
                        if (sameProperties.Count >= 1)
                        {
                            foreach (var sameProperty in sameProperties)
                            {
                                if (sameProperty.Key == columnName)
                                {
                                    property = sameProperty.Value;
                                }
                            }
                            if (property == null)
                            {
                                property = sameProperties.First().Value;
                            }
                        }
                        else
                        {
                            throw new ApplicationException("未找到指定的排序列。");
                        }
                        if (propertyAccess == null)
                        {
                            propertyAccess = Expression.Property(parameter, property);
                        }
                        else
                        {
                            propertyAccess = Expression.Property(propertyAccess, property);
                        }
                    }
                    string orderByName;
                    switch (sorting.OrderByMode)
                    {
                        case OrderByMode.Asc:
                            orderByName = "OrderBy";
                            break;
                        case OrderByMode.Desc:
                            orderByName = "OrderByDescending";
                            break;
                        default:
                            throw new ApplicationException("未知排序枚举。");
                    }
                    query = query.Provider.CreateQuery<T>(Expression.Call(typeof(Queryable), orderByName, new Type[] { entityType, property.PropertyType }, query.Expression, Expression.Lambda(propertyAccess, parameter)));
                }
            }
            return query;
        }
    }
}
